// phalanx container_traits.hpp.cu header file

// Copyright (c) 2011 - 2011 Kohei Takahashi (Flast).
// Distributed under the MIT license. for more detail see COPYING.

#ifndef IG_PHALANX_ITERATOR_DETAIL_CONTAINER_TRAITS_HPP_CU_ONCE_
#define IG_PHALANX_ITERATOR_DETAIL_CONTAINER_TRAITS_HPP_CU_ONCE_

#include <phalanx/config.hpp.cu>

#include <boost/mpl/if.hpp>
#include <boost/mpl/placeholders.hpp>

#include <phalanx/detail/sfinae_helper.hpp.cu>

#include <phalanx/type_traits/builtin_traits.hpp.cu>
#include <phalanx/type_traits/is_builtin_vector.hpp.cu>
#include <phalanx/type_traits/is_const.hpp.cu>
#include <phalanx/type_traits/remove_const.hpp.cu>

#include <phalanx/utility/apply_if.hpp.cu>

namespace phalanx
{

namespace iterator_detail
{

template < typename C >
struct _traits_wrapper
{
    template < typename T >
    struct apply_traits
    { typedef vector_type_traits< T > type; };

    typedef typename remove_const< C >::type container_type;
    typedef typename apply_if<
      is_builtin_vector< container_type >,
      apply_traits< ::boost::mpl::_1 >,
      container_type >::type type;
};

#define LO_PHALANX_DEDUCER_DEF( type_name_ ) \
  template < typename C, typename = void > \
  struct _ ## type_name_{}; \
  \
  template < typename C > \
  struct _ ## type_name_< \
    C, \
    typename sfinae_detail::sfinae_helper< \
      typename _traits_wrapper< C >::type::type_name_ >::type > \
  { typedef typename _traits_wrapper< C >::type::type_name_ type; }


LO_PHALANX_DEDUCER_DEF( value_type );
LO_PHALANX_DEDUCER_DEF( size_type );
LO_PHALANX_DEDUCER_DEF( difference_type );
LO_PHALANX_DEDUCER_DEF( pointer );
LO_PHALANX_DEDUCER_DEF( const_pointer );
LO_PHALANX_DEDUCER_DEF( reference );
LO_PHALANX_DEDUCER_DEF( const_reference );

#undef LO_PHALANX_DEDUCER_DEF

} // namespace iterator_detail

template < typename C >
struct container_value
  : public iterator_detail::_value_type< C > {};

template < typename C >
struct container_size
  : public iterator_detail::_size_type< C > {};

template < typename C >
struct container_difference
  : public iterator_detail::_difference_type< C > {};

template < typename C >
struct container_pointer
  : public ::boost::mpl::if_< is_const< C >,
      iterator_detail::_const_pointer< C >,
      iterator_detail::_pointer< C > >::type {};

template < typename C >
struct container_reference
  : public ::boost::mpl::if_< is_const< C >,
      iterator_detail::_const_reference< C >,
      iterator_detail::_reference< C > >::type {};

} // namespace phalanx

#endif // IG_PHALANX_ITERATOR_DETAIL_CONTAINER_TRAITS_HPP_CU_ONCE_

